﻿using System;
using SlimDX.Direct3D11;
using SlimDX;
using SlimDX.D3DCompiler;
using SlimDX.DXGI;

namespace LabyrinthGame
{
    public class Cell
    {
        /*-----------
         * Variables
         *-----------*/

        //Coordinates
        public int x { get; private set; }
        public int y { get; private set; }
        public int z { get; private set; }
        public bool isWall { get; private set; }

        //Player information //nothing
        public Player player { get; private set; }

        //Important numbers to resize
        private static float scale = 0.1f;
        private float mod = 0;

        //SlimDX parameters
        private Viewport2D viewport;
        private SlimDX.Direct3D11.Buffer vertexBuffer;
        private InputLayout layout;
        private Vector3[] vectors = new Vector3[4];

        //Shaders
        private VertexShader vertexShader;
        private ShaderSignature shaderSignature;
        private PixelShader pixelShader;

        /*---------------
         * Constructors
         *--------------*/
        public Cell(int x, int y, float mod, Viewport2D viewport)
        {
            this.mod = mod;
            this.x = x;
            this.y = y;
            this.z = 0;
            this.isWall = false;
            this.viewport = viewport;
            initShaders();
            initVertexes();
        }
        public Cell(int x, int y, int z, float mod, bool isWall, Viewport2D viewport)
        {
            this.mod = mod;
            this.x = x;
            this.y = y;
            this.z = z;
            this.isWall = isWall;
            this.viewport = viewport;
            initShaders();
            initVertexes();
        }

        /*---------
         * Methods
         *---------*/
        private void initVertexes()
        {
            /*left up
             *right up
             *right down
             *left down
             */
            vectors = new Vector3[] { 
                new Vector3(x*scale*mod, (y + 1)*scale, z), 
                new Vector3((x + 1)*scale*mod, (y + 1)*scale, z),
                new Vector3((x + 1)*scale*mod, y*scale, z),
                new Vector3(x*scale*mod, y*scale, z)
            };

            using (var vertices = new DataStream(Vector3.SizeInBytes * 6, true, true))
            {
                vertices.Write(vectors[0]);
                vertices.Write(vectors[1]);
                vertices.Write(vectors[2]);
                vertices.Write(vectors[0]);
                vertices.Write(vectors[2]);
                vertices.Write(vectors[3]);
                vertices.Position = 0;

                var elements = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0) };
                layout = new InputLayout(viewport.device, shaderSignature, elements);
                vertexBuffer = new SlimDX.Direct3D11.Buffer(viewport.device, vertices, Vector3.SizeInBytes * 6, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
            }

        }
        private void initShaders()
        {
            using (var bytecode = ShaderBytecode.CompileFromFile("Effects.fx", "VShader", "vs_4_0", ShaderFlags.Debug, EffectFlags.None))
            {
                shaderSignature = ShaderSignature.GetInputSignature(bytecode);
                vertexShader = new VertexShader(viewport.device, bytecode);
            }
            if (isWall)
                using (var bytecode = ShaderBytecode.CompileFromFile("Effects.fx", "RedShader", "ps_4_0", ShaderFlags.Debug, EffectFlags.None))
                {
                    pixelShader = new PixelShader(viewport.device, bytecode);
                }
            else
                using (var bytecode = ShaderBytecode.CompileFromFile("Effects.fx", "PShader", "ps_4_0", ShaderFlags.Debug, EffectFlags.None))
                {
                    pixelShader = new PixelShader(viewport.device, bytecode);
                }
        }
        private void prepareForDraw()
        {
            viewport.context.InputAssembler.InputLayout = layout;
            viewport.context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            viewport.context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, Vector3.SizeInBytes, 0));

            // set the shaders
            viewport.context.VertexShader.Set(vertexShader);
            viewport.context.PixelShader.Set(pixelShader);
        }
        public void moveTo(int newX, int newY)
        {
            x = newX;
            y = newY;
            initVertexes();
        }
        public void draw()
        {
            prepareForDraw();
            viewport.context.Draw(6, 0);
        }
    }
}
